package main

import (
	"encoding/json"
	"fmt"
	"github.com/360EntSecGroup-Skylar/excelize"
	"io"
	"io/ioutil"
	"net/http"
	"os"
	"strconv"
	"strings"
	"time"
)

type RootName struct {
	Ok   int  `json:"ok"`
	Data Data `json:"data"`
}
type Data struct {
	IsVideoCoverStyle int `json:"isVideoCoverStyle"`
	IsStarStyle       int `json:"isStarStyle"`
	UserInfo          struct {
		Id                int64  `json:"id"`
		ScreenName        string `json:"screen_name"`
		ProfileImageUrl   string `json:"profile_image_url"`
		ProfileUrl        string `json:"profile_url"`
		StatusesCount     int    `json:"statuses_count"`
		Verified          bool   `json:"verified"`
		VerifiedType      int    `json:"verified_type"`
		VerifiedTypeExt   int    `json:"verified_type_ext"`
		VerifiedReason    string `json:"verified_reason"`
		CloseBlueV        bool   `json:"close_blue_v"`
		Description       string `json:"description"`
		Gender            string `json:"gender"`
		Mbtype            int    `json:"mbtype"`
		Urank             int    `json:"urank"`
		Mbrank            int    `json:"mbrank"`
		FollowMe          bool   `json:"follow_me"`
		Following         bool   `json:"following"`
		FollowCount       int    `json:"follow_count"`
		FollowersCount    string `json:"followers_count"`
		FollowersCountStr string `json:"followers_count_str"`
		CoverImagePhone   string `json:"cover_image_phone"`
		AvatarHd          string `json:"avatar_hd"`
		Like              bool   `json:"like"`
		LikeMe            bool   `json:"like_me"`
		ToolbarMenus      []struct {
			Type   string `json:"type"`
			Name   string `json:"name"`
			Pic    string `json:"pic"`
			Params struct {
				Uid       int64 `json:"uid,omitempty"`
				Extparams struct {
					Followcardid string `json:"followcardid"`
				} `json:"extparams,omitempty"`
				Scheme string `json:"scheme,omitempty"`
			} `json:"params"`
			UserInfo struct {
				Id                  int64  `json:"id"`
				Idstr               string `json:"idstr"`
				ScreenName          string `json:"screen_name"`
				ProfileImageUrl     string `json:"profile_image_url"`
				Following           bool   `json:"following"`
				Verified            bool   `json:"verified"`
				VerifiedType        int    `json:"verified_type"`
				Remark              string `json:"remark"`
				AvatarLarge         string `json:"avatar_large"`
				AvatarHd            string `json:"avatar_hd"`
				VerifiedTypeExt     int    `json:"verified_type_ext"`
				FollowMe            bool   `json:"follow_me"`
				Mbtype              int    `json:"mbtype"`
				Mbrank              int    `json:"mbrank"`
				Level               int    `json:"level"`
				Type                int    `json:"type"`
				StoryReadState      int    `json:"story_read_state"`
				AllowMsg            int    `json:"allow_msg"`
				FriendshipsRelation int    `json:"friendships_relation"`
				CloseFriendsType    int    `json:"close_friends_type"`
				SpecialFollow       bool   `json:"special_follow"`
			} `json:"userInfo,omitempty"`
			Scheme string `json:"scheme,omitempty"`
		} `json:"toolbar_menus"`
	} `json:"userInfo"`
	FansScheme   string `json:"fans_scheme"`
	FollowScheme string `json:"follow_scheme"`
	TabsInfo     struct {
		SelectedTab int `json:"selectedTab"`
		Tabs        []struct {
			Id          int    `json:"id"`
			TabKey      string `json:"tabKey"`
			MustShow    int    `json:"must_show"`
			Hidden      int    `json:"hidden"`
			Title       string `json:"title"`
			TabType     string `json:"tab_type"`
			Containerid string `json:"containerid"`
			Apipath     string `json:"apipath,omitempty"`
			TabIcon     string `json:"tab_icon,omitempty"`
			TabIconDark string `json:"tab_icon_dark,omitempty"`
			Url         string `json:"url,omitempty"`
		} `json:"tabs"`
	} `json:"tabsInfo"`
	Scheme      string `json:"scheme"`
	ShowAppTips int    `json:"showAppTips"`
}

func main() {
	var uid string
	fmt.Println("请输入用户ID:")
	fmt.Scanf("%s\n", &uid)
	os.MkdirAll("照片/"+uid, os.ModePerm)
	os.MkdirAll("视频/"+uid, os.ModePerm)
	os.MkdirAll("微博/", os.ModePerm)
	data := getData(uid)
	getUserInfo(data)
	var containerId string
	for i := range data.TabsInfo.Tabs {
		if data.TabsInfo.Tabs[i].TabType == "weibo" {
			containerId = data.TabsInfo.Tabs[i].Containerid
		}
	}
	getWeibo(containerId, uid)
}

func getWeibo(containerId, uid string) {
	i := 1
	num := 0
	weiboNum := 1
	videoNum := 0
	fmt.Println("是否要爬取图片?(Yes/No)")
	var flag string
	fmt.Scanf("%s\n", &flag)
	fmt.Println("开始")
	date := time.Now().Format("2006-01-02")
	name := "./微博/" + uid + "-" + date + ".xlsx"
	file := excelize.NewFile()
	file.SetCellValue("Sheet1", "A"+strconv.Itoa(weiboNum), weiboNum-1)
	file.SetCellValue("Sheet1", "B"+strconv.Itoa(weiboNum), "UID")
	file.SetCellValue("Sheet1", "C"+strconv.Itoa(weiboNum), "内容")
	file.SetCellValue("Sheet1", "D"+strconv.Itoa(weiboNum), "时间")
	file.SetCellValue("Sheet1", "E"+strconv.Itoa(weiboNum), "类型")
	for {
		weiboUrl := "https://m.weibo.cn/api/container/getIndex?type=uid&value=" + uid + "&containerid=" + containerId + "&page=" + strconv.Itoa(i)
		resp, err := http.Get(weiboUrl)
		if err != nil {
			fmt.Println("getWeibo err:", err)
		}
		bytes, err := ioutil.ReadAll(resp.Body)
		if err != nil {
			fmt.Println("getWeibo readAll err:", err)
		}
		var weibo WeiBo
		json.Unmarshal(bytes, &weibo)
		if weibo.Ok == 0 {
			fmt.Println("结束！！！")
			break
		}
		cards := weibo.Data.Cards
		for _, card := range cards {
			weiboNum++
			fmt.Println("正在爬取第" + strconv.Itoa(weiboNum) + "条微博...")
			file.SetCellValue("Sheet1", "A"+strconv.Itoa(weiboNum), weiboNum-1)
			file.SetCellValue("Sheet1", "B"+strconv.Itoa(weiboNum), uid)
			file.SetCellValue("Sheet1", "C"+strconv.Itoa(weiboNum), card.Mblog.Text)
			file.SetCellValue("Sheet1", "D"+strconv.Itoa(weiboNum), card.Mblog.CreatedAt)
			if card.Mblog.RetweetedStatus.IsEmpty() {
				file.SetCellValue("Sheet1", "E"+strconv.Itoa(weiboNum), "原创")
				if strings.EqualFold(flag, "yes") || strings.EqualFold(flag, "y") {
					for _, pic := range card.Mblog.Pics {
						picPath := pic.Large.Url
						index := strings.LastIndex(picPath, ".")
						picResp, err := http.Get(picPath)
						if err != nil {
							fmt.Println("get pic err:", err)
						}
						create, _ := os.Create("./照片/" + uid + "/pic" + strconv.Itoa(num) + picPath[index:])
						io.Copy(create, picResp.Body)
						num++
					}
					if card.Mblog.PageInfo.MediaInfo.StreamUrlHd != "" {
						mediaResp, err := http.Get(card.Mblog.PageInfo.MediaInfo.StreamUrlHd)
						if err != nil {
							fmt.Println("get video err:", err)
						}
						create, _ := os.Create("./视频/" + uid + "/media" + strconv.Itoa(videoNum) + ".mp4")
						io.Copy(create, mediaResp.Body)
						videoNum++
					}
				}
			} else {
				file.SetCellValue("Sheet1", "E"+strconv.Itoa(weiboNum), "非原创")
			}

		}
		i++
		time.Sleep(500)
	}
	if err := file.SaveAs(name); err != nil {
		fmt.Println(err)
	}
}

func getData(uid string) *Data {
	path := "https://m.weibo.cn/api/container/getIndex?type=uid&value=" + uid
	resp, err := http.Get(path)
	if err != nil {
		fmt.Println("http get err:", err)
	}

	bytes, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Println("readAll err:", err)
	}
	var rt RootName
	json.Unmarshal(bytes, &rt)
	return &rt.Data
}

func getUserInfo(data *Data) {
	var info = data.UserInfo
	fmt.Printf("微博昵称:%s\n微博主页地址:%s\n微博头像:%s\n性别:%s\n微博说明:%s\n微博关注数:%d\n微博粉丝数:%s\n",
		info.ScreenName, info.ProfileUrl, info.ProfileImageUrl, info.Gender, info.Description, info.FollowCount, info.FollowersCount)
}
